package com.zshan.clinic.web.handler;


import com.zshan.clinic.admin.task.AsyncTaskService;
import com.zshan.clinic.common.constant.CommonConstant;
import com.zshan.clinic.common.exception.BusinessFailException;
import com.zshan.clinic.common.exception.SystemFailException;
import com.zshan.clinic.common.response.RestResp;
import com.zshan.clinic.common.util.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;


/**
 * controller  异常统一处理
 */
@ControllerAdvice
@Slf4j
public class ExceptionHandler {


    @Autowired
    private AsyncTaskService asyncTaskService;


    @org.springframework.web.bind.annotation.ExceptionHandler(SystemFailException.class)
    @ResponseBody
    public RestResp<Void> handleSystemFailExceptionn(HttpServletRequest request, SystemFailException ex) {
        log.error(ex.getMessage(), ex);
        return RestResp.SYSTEM_FAIL(ex.getMessage());
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(BusinessFailException.class)
    @ResponseBody
    public RestResp<Void> handleBusinessFailException(HttpServletRequest request, BusinessFailException ex) {
        log.error(ex.getMessage(), ex);
        String code = ex.getCode();
        if(StringUtil.isBlank(code)){
            return RestResp.BUSINESS_FAIL(ex.getMessage());
        }else{
            return RestResp.FAIL(code,ex.getMessage());
        }
    }

    @org.springframework.web.bind.annotation.ExceptionHandler({MissingServletRequestParameterException.class, MethodArgumentTypeMismatchException.class, BindException.class, HttpMessageNotReadableException.class})
    @ResponseBody
    public RestResp<Void> handleMissingServletRequestParameterException(Exception ex) {
        log.warn("参数校验异常: {}", ex.getMessage(), ex);
        return RestResp.BUSINESS_FAIL("请求参数不合法");
    }

    @org.springframework.web.bind.annotation.ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public RestResp<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.warn("参数校验异常: {}", ex.getMessage(), ex);
        // 提取第一个错误信息
        String errorMsg = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .findFirst()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .orElse("参数错误");
        return RestResp.BUSINESS_FAIL(errorMsg);
    }


    @org.springframework.web.bind.annotation.ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
    @ResponseBody
    public RestResp<Void> handleHttpMediaTypeNotAcceptableException(HttpMediaTypeNotAcceptableException ex) {
        log.warn("不支持的响应媒体类型：{}", ex.getMessage(), ex);
        return RestResp.BUSINESS_FAIL("不支持的响应类型，请检查请求头 Accept");
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
    @ResponseBody
    public RestResp<Void> handleException(HttpServletRequest request, Exception ex) {
        String errorInfo = "网页服务出现异常,请求地址:" + request.getRequestURI() + "，异常信息:" + ex.getMessage();
        log.error(errorInfo, ex);
        StringWriter stringWriter = new StringWriter();
        ex.printStackTrace(new PrintWriter(stringWriter));
        asyncTaskService.sendMail(CommonConstant.SYSTEM_EXCEPTION, errorInfo, stringWriter.toString());
        return RestResp.SYSTEM_FAIL("网络异常");
    }
}
